feat(linux): ship a Flatpak bundle with each release - #767
Conversation
Greptile SummaryThe PR adds amd64 and arm64 Flatpak bundles to the existing Linux packaging and release pipeline.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| .github/workflows/build.yml | Adds architecture-verified Flatpak builds, workspace-derived AppStream stamping, bundle creation, and reusable-workflow result reporting. |
| .github/workflows/release.yml | Incorporates available Flatpak bundles into the existing best-effort Linux release, checksum, signing, R2, and GitHub publication paths. |
| packaging/linux/flatpak/org.openlogi.OpenLogi.yml | Defines the Flatpak runtime, sandbox permissions, build environment, complete binary set, desktop integration, icons, udev rules, and licenses. |
| packaging/linux/flatpak/org.openlogi.OpenLogi.metainfo.xml | Adds AppStream metadata whose release version and date are replaced during CI from the checked-out source tree. |
| docs/INSTALL-linux.md | Documents bundle installation, the lack of an update remote, and the mandatory host-side udev setup. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
S[Checked-out release tree] --> B[Flatpak matrix build]
B --> X[amd64 bundle]
B --> A[arm64 bundle]
X --> P[Release publisher]
A --> P
P --> C[SHA-256 checksums]
P --> M[Minisign signatures]
C --> G[GitHub Release and R2]
M --> G
Reviews (5): Last reviewed commit: "docs(linux): document the Flatpak bundle..." | Re-trigger Greptile
|
Both review findings are resolved. Version/ref mismatch (P1). Fixed in Action pinning (P2). Settled as a non-issue for this workflow: every action in the publish job is first-party CI status. Green on |
|
Thanks for the approval. One thing to flag before v0.7.5 ships: publishing is gated on a FLATPAK_GPG_PRIVATE_KEY repository secret. Without it the workflow still builds both architectures and uploads artifacts, but the publish job skips and no repository is deployed, so the remote that users would add based on the docs wouldn't exist yet. Whoever sets the key will also need to set GitHub Pages to deploy from GitHub Actions. Happy to write up the key generation steps if that's useful. |
Great call out @AprilNEA would have the update the ENV variable before going live :) |
|
Just to clarify where it goes, it's a repository secret rather than an env variable, under |
|
I ran the numbers on what a Flatpak userbase would put through this remote, which I should have done before opening the PR, and Pages doesn't hold up as I didn't take into account how many users use this app. Upstream releases about 17 times a month, and a full pull is roughly 31.5 MiB per arch. At a few thousand people updating, that's somewhere between 200 GB and 1 TB a month against a 100 GB allowance on GitHub Pages. Deltas help but they can't close a 5x gap, since at this release cadence people are often more than one commit behind and the delta stops applying. I'd also like to have a go at getting this onto Flathub. It needs vendored offline builds. I've scoped that out and it's doable, but realistically a few weeks of verification to get approved. So for the meantime, two options, rather than me rewriting this PR unasked:
Whoever owns the bucket ends up owning the signing key and the bill, so that part is your call either way. Since writing this I've put option 2 up so you can look at it working: Same manifest as this PR with the publish switched to R2. Signed commits verify, the history goes back to v0.7.2 so deltas have something to apply against (about 3 MB for a one release jump instead of 31 MB), and with the cache rules in front of it everything sits inside the free tier. Each release there also carries the bundles from option 1, so both options are visible in one place. This is a stopgap running on my own account, not me trying to own the Linux distribution. If you'd rather run it yourselves I'll hand the workflow over as is, and whenever that happens or Flathub lands, I'll archive mine and point people at yours. |
|
Please make it so it goes on Flathub. It will show up in everyone's app stores. |
|
Dropping the repo and starting with |
|
Want your agent to iterate on Greptile's feedback? Start a greploop in Codex and it will work through the open comments and keep going until this PR reviews clean. |
The .deb/.rpm/.pkg.tar.zst cover the distributions that use them, and leave out the ones that use neither: the immutable distributions especially, where Flatpak is simply how software is installed. This adds a single-file .flatpak bundle per architecture to the release assets, beside the packages already there. A bundle is a one-time install rather than a subscription, since there is no remote for `flatpak update` to check. That is the deliberate limit of this change: closing it needs a repository to host and sign, which is a bigger decision than adding a build artifact, and it can be taken later without undoing any of this. The build is its own leg rather than part of linux-packages. It compiles the workspace again inside the Flatpak SDK, where the runner's rust-cache cannot reach, so folding it in would tie a thirty-minute job to an hour-long one and lose the .deb whenever the Flatpak build failed. It rides the same best-effort path as the Windows and Linux package legs: a failure costs the bundle, not the release. AppStream is stamped from the tree being built, never from an input. The version comes from the workspace and the date from the commit, so a rebuild of an old tag cannot claim to have been released the day it was rebuilt, and the label cannot drift from the binaries it names. Verified locally end to end: flatpak-builder and build-bundle both exit 0, and the resulting 23 MB bundle imports with all four binaries, the stamped version, the udev rules, every icon size and the runtime repo embedded.
The Linux section listed the three package formats and nothing for the distributions that use none of them, which is the gap the bundle exists to fill. Host setup is one command rather than the usual block. The rules are read out of the installed application, so it needs no checkout and no cloned repository, and nothing extra is needed for /dev/uinput: the rules already create its node with static_node=uinput and opening it loads the module, which is why no packaging here ships a modules-load.d entry either. Also says what the bundle is not. There is no remote behind it, so `flatpak update` has nothing to check, and the agent is launched by the application rather than by a user service — so the systemctl line below it does not apply. Verified the one-liner against an installed bundle: it reproduces the tracked rules file byte for byte.
The minisign loop covers the DMGs, the Windows zip/msi and all three Linux package formats, and its own comment says why: manual verification today, and the future auto-updaters need a detached signature to exist for every shipped version. The bundle was left out of it. That mattered in two places, not one. It is attached to the GitHub Release, and the R2 step copies dist/ wholesale, so the bundle was already being published to both without a .minisig beside it — the one installer a user could not verify. The signatures themselves need no further wiring: dist/*.minisig is already listed unconditionally in the release assets and R2 excludes only latest.json and the exes. Reported by Greptile on AprilNEA#957.
Carries across the INSTALL-linux.md section from the repository-based approach, rewritten for a bundle: no remote to add, so no auto-update, and the udev step is the same one command rather than five. Two of those five were never needed. The rules already create /dev/uinput at boot with static_node=uinput and opening it loads the module, which is why no packaging in this tree ships a modules-load.d entry either. Also records the new build leg in the CI rules, including that the label gate means a PR touching the manifest gets no feedback until someone applies it.
6a26bcb to
f68a013
Compare
|
I've reworked this to drop the repository half. It now only builds the The reason is the numbers I posted above: Pages does not carry the traffic a So the earlier What it does not do: bundles have no remote behind them, so Both arch legs build green in CI and the amd64 bundle installs and runs. One Also fixed a Greptile P1 from the closed duplicate: the minisign loop covers |
Summary
Adds a
.flatpakbundle per architecture to the release assets, beside the.deb/.rpm/.pkg.tar.zstalready there. One new job in the existing buildmatrix, and a few edits to
release.ymlto sign and attach what it produces.This PR has been reworked and no longer publishes a repository. It opened
as a signed OSTree repository on Pages, which meant a workflow to run, a GPG
key to hold, and hosting to keep alive. Since then I ran the numbers on what a
Flatpak userbase would actually pull through such a remote, and Pages does not
hold up (see the earlier comment in this thread). Rather than ask you to adopt
R2 and a signing key on my say-so, this is now the part that needs none of it.
What that costs: a bundle is a one-time install. There is no remote behind it,
so
flatpak updatehas nothing to check. That is a real limitation and it isstated plainly in the docs. It also does not close #605. What it does give you
is an install path for atomic distributions (#681), where layering an rpm is
the current answer, at the price of one job in a matrix.
Adding a repository later is still possible and nothing here works against it —
the manifest, metadata and build steps are the same either way. That decision
just stops being a condition of merging this.
No new workflow file, no OSTree repo, no signing key, no hosting.
Changes
packaging/linux/flatpak/(new)org.openlogi.OpenLogi.yml, the manifest. Source istype: dirover thecheckout, so a release build is exactly the tagged tree.
.desktopand AppStream metadata. Flatpak requires both to be named for theapplication ID, which the packaged
.desktopis not, and there is noAppStream data in the tree, which software centres need to list the app.
Only the build environment lives in the manifest, because that part is
genuinely packaging's problem:
org.freedesktop.Sdk.Extension.rust-stable. The workspacesets
rust-versionto current stable and the extension trails it by weeks(1.97.1 against a workspace asking for 1.98), which cargo refuses outright.
rustup installs what
rust-toolchain.tomlnames.llvm20, becauseopenlogi-camerapullsv4l2-sys-mit, whose build scriptruns bindgen and dlopens libclang. The base SDK ships none.
Permissions worth a look:
--device=allis the only one covering both/dev/hidraw*and/dev/uinput—--device=inputcovers neither. It grants apath to those nodes, not DAC permission; the host still needs
70-openlogi.rules, exactly as the.debdoes. Solaar carries the samepermission on Flathub for the same reason.
.github/workflows/build.ymlNew
linux-flatpakjob, matrixamd64/arm64on the same runners aslinux-packages, wired intoresultsand theworkflow_calloutputs.Separate from
linux-packageson purpose: it compiles the workspace againinside the Flatpak SDK, where the runner's rust-cache cannot reach, so folding
them together would lose the
.debwhenever the Flatpak build failed.AppStream is stamped from the tree — version from the workspace, date from the
commit — never from an input, so a rebuild of an old tag cannot claim to have
been released the day it was rebuilt.
.github/workflows/release.ymlDownloads the artifacts, adds
*.flatpaktoSHA256SUMSand to the minisignloop, and attaches the bundles best-effort. It rides the existing degradation
path:
publishgates only onmacos_result, so a failed Flatpak leg costs thebundle, not the release.
Docs —
README.mdanddocs/INSTALL-linux.mdcover the install and theone-time host udev setup, which is a single command.
.claude/rules/ci.mdrecords the new leg and its label gate.
Testing
Dispatched
Releaseon the branch (publish skipped,ref_type != 'tag'):linux-flatpak (amd64)— passlinux-flatpak (arm64)— passexpected and unrelated
Locally, from the repository root:
Both exit 0 in ~10 minutes; metainfo and desktop validate. Re-imported the
bundle and confirmed the contents: all four binaries, the stamped version,
70-openlogi.rules, every icon size, and the runtime repo embedded.Installed the amd64 CI artifact on Fedora 44 and confirmed it runs.
Not runtime-tested against hardware beyond that — device access depends on
the host udev rules, which that machine already had.
The
release.ymlhalf is not exercised by any of the above, becausepublishneeds a tag and a successful macOS leg, which a fork cannot produce. I ran its
shell against a fabricated
dist/instead: with bundles present both land inSHA256SUMS, get signed, and are attached; with the leg failed, checksums stillgenerate and
fail_on_unmatched_filesdoes not trip.Notes for review
should-buildreturnsfalseforpull_requestwithout theneeds: buildlabel, so a green check here has notrun the new job.
publishhasneeds: build, so a release now waits for the Flatpak legs eventhough it does not depend on them. Measured ~15 minutes cold on
ubuntu-latest;timeout-minutes: 45is a hang bound, not an estimate.Refs #605, #681.
Fix #371